import { Card, Table, App, Alert } from 'antd';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { AdvancedSearch } from '../AdvancedSearch';
import { ColumnsType, ColumnType } from 'antd/es/table';
import { LibAppView } from '@/lib';
import { useIntl } from 'react-intl';

interface IResourceListProps {
    searchFields: Admin.IAdvancedField[];
    tableColumns: ColumnsType<any>;
    listEndPoint: {
        endPoint: string;
        formatResponse?: <T={}>(resp: any) => T[];
        formatRequest?: (searchData: any) => any;
        formatUri?: (pagination: any) => any;
    },
    pageSize?: number;
    AlertMessage?: React.ComponentType<any>;
    Operators?: React.ComponentType<any>;
    tableWidth?: number|string;
    refApi?: any;
    minHeight?: any;
    onChange?: (data: any[]) => void;
    expandColumns?: ColumnsType<any>;
    expandSourceName?: string;
    idName?: string;
}

export const ResourceList = LibAppView.withService<IResourceListProps>()(
    ({
    searchFields,
    tableColumns,
    withServiceApi,
    listEndPoint,
    pageSize,
    AlertMessage,
    Operators,
    refApi,
    ...others
}) => {
    const [ fromSessionData ] = useState(() => {
        const fromStorage = sessionStorage.getItem("resourceListSearchData");
        if(fromStorage && fromStorage.length > 0) {
            const data = JSON.parse(fromStorage);
            if(data.endPoint === listEndPoint?.endPoint) {
                return data;
            } else {
                sessionStorage.removeItem("resourceListSearchData");
                return {};
            }
        } else {
            return {};
        }
    });
    const [ loading, setLoading ] = useState(true);
    const [ listData, setListData ] = useState<any[]>([]);
    const [ searchData, setSearchData] = useState<any>(fromSessionData || {});
    const [ page, setPage ] = useState(() => fromSessionData.page || 1);
    const [ pageLimitSize, setPageLimitSize ] = useState(fromSessionData.pageSize || 10);
    const [ totalPage, setTotalPage ] = useState(() => fromSessionData.totalPage || 0); 
    const [ totalCount, setTotalCount] = useState(() => fromSessionData.totalCount || 0);
    const intl = useIntl();
    const antApp = App.useApp();
    const onSearchChange = useCallback((values: any) => {
        setSearchData({...values});
    }, []);

    const rowRender = useMemo(() => {
        return (srcColumns: ColumnType<any>) => {
            if(srcColumns.render) {
                const idKeyName = others.idName || "id";
                return (value: any, data: any, index: number) => {
                    return srcColumns.render ? srcColumns.render(value, data, {
                        index,
                        setData: (rowData: any) => {
                            setListData(listData.map((item: any) => {
                                if(item[idKeyName] === data[idKeyName]) {
                                    return {
                                        ...item,
                                        ...rowData
                                    };
                                } else {
                                    return item;
                                }
                            }));
                        }
                    } as any) as any : value;
                };
            } else {
                return null;
            }
        };
    }, [listData, others.idName]);

    const tableColumsData = useMemo<any[]>(() => (tableColumns || []).map((item) => {
        if(item.render) {
            return {
                ...item,
                render: rowRender(item)
            };
        } else {
            return item;
        }
    }), [tableColumns, listData]);
    const pagination = useMemo(() => ({
        current: page,
        pageSize: pageLimitSize,
        total: totalCount
    }), [page, pageLimitSize, totalCount]);
    const refreshData = useCallback(() => {
        const searchRequest = typeof listEndPoint?.formatRequest === "function" ? listEndPoint?.formatRequest(searchData) : searchData;
        const searchBody = {
            ...searchRequest,
            page: page - 1,
            pageSize: pageLimitSize,
            totalPage,
            totalCount
        };
        setLoading(true);
        withServiceApi.send({
            endPoint: listEndPoint?.endPoint,
            data: searchBody,
            uri: typeof listEndPoint?.formatUri === "function" ? listEndPoint?.formatUri(pagination) : undefined
        }).then((resp: any) => {
            const data: any[] = (listEndPoint?.formatResponse ? listEndPoint?.formatResponse(resp) : resp.data) || [];
            const totalPageValue = resp.totalPage || 1;
            const totalCountValue = resp.totalCount || data.length || 0;
            if(totalPage !== totalPageValue) {
                setTotalPage(totalPageValue);
            }
            if(page <= 1 && totalCountValue !== totalCount) {
                setTotalCount(totalCountValue);
            }
            const newListData = data.map((v, index) => ({...v, key: index}));
            setListData(newListData);
            setLoading(false);
            if(refApi && (refApi as any).current) {
                (refApi as any).current.searchData = searchBody;
            }
            sessionStorage.setItem("resourceListSearchData", JSON.stringify({
                ...searchBody,
                endPoint: listEndPoint?.endPoint
            }));
            typeof others.onChange === "function" && others.onChange(newListData);
        }).catch((err) => {
            const msg = intl.formatMessage({
                id: `error.${err.statusCode || err.status}`,
                defaultMessage: err.message || "系统错误，服务不可用"
            });
            setLoading(false);
            antApp.message.error(msg);
            console.error(err);
        });
    }, [searchData, listEndPoint, pageLimitSize, page, totalPage, totalCount]);
    const handleTableChange = useCallback((pagination: any) => {
        setPage(pagination.current);
        setPageLimitSize(pagination.pageSize);
    }, []);
    const alertStyle = useMemo(() =>({
        paddingBottom: 20
    }), []);
    const alertData = useMemo(() => ({
        pagination
    }), [pagination]);

    const expandConfig = useMemo(() => {
        if(others.expandColumns) {
            return {
                expandable: {
                    expandedRowRender: (exprops: any) => {
                        const sourceName = others.expandSourceName || "children";
                        return <Table
                            columns={others.expandColumns?.map((item) => {
                                if(item.render) {
                                    return {
                                        ...item,
                                        render: rowRender(item)
                                    } as any;
                                } else {
                                    return item;
                                }
                            })}
                            dataSource={exprops[sourceName] || []}
                            pagination={false}
                        />
                    },
                    defaultExpandedRowKeys: ['0']
                }
            }
        }
        return {};
    }, [others.expandColumns]);
    useEffect(() => {
        if(refApi) {
            if(typeof refApi === "function") {
                refApi({
                    refreshData: refreshData,
                    showLoading: () => setLoading(true),
                    hideLoading: () => setLoading(false)
                });
            } else {
                (refApi as any).current = {
                    refreshData: refreshData,
                    showLoading: () => setLoading(true),
                    hideLoading: () => setLoading(false)
                };
            }
        }
    }, []);
    useEffect(() => {
        refreshData();
    }, [searchData, page, pageLimitSize]);
    return (
        <Card style={{ width: "100%", minHeight: others.minHeight || "69vh" }}>
            { searchFields && searchFields.length > 0 && <AdvancedSearch collapse initData={searchData} onChange={onSearchChange} fields={searchFields || []} />}
            { Operators && <Operators /> }
            { AlertMessage && <div style={alertStyle}>
                <Alert message={<AlertMessage data={alertData}/>} type="info" showIcon />
            </div>}
            <Table
                loading={loading}
                dataSource={listData}
                columns={tableColumsData}
                scroll={{ x: others.tableWidth || 1600 }}
                pagination={pagination}
                bordered
                onChange={handleTableChange}
                {...expandConfig}
            />
        </Card>
    );
});
